package com.cjack.frenchexcel.service;

import com.cjack.frenchexcel.config.CommonConfig;
import com.cjack.frenchexcel.config.LayPage;
import com.cjack.frenchexcel.config.PrivateConfig;
import com.cjack.frenchexcel.dao.*;
import com.cjack.frenchexcel.enumInfo.DataDefineTypeEnum;
import com.cjack.frenchexcel.model.ConsumerRecordModel;
import com.cjack.frenchexcel.model.GoodsModel;
import com.cjack.frenchexcel.table.*;
import com.cjack.frenchexcel.util.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * Created by root on 10/5/19
 */
@Service
public class GoodsService {

    @Autowired
    private GoodsDao dao;
    @Autowired
    private UserAdminDao userAdminDao;
    @Autowired
    private DataDefineDao dataDefineDao;
    @Autowired
    private ConsumerRecordDao consumerRecordDao;
    @Autowired
    private SystemparamDao systemparamDao;

    @Value("${file.upload.baseServerDir}")
    String baseServerDir;
    @Value("${file.upload.baseClientDir}")
    String baseClientDir;


    public Page< GoodsTable> list( LayPage page, GoodsModel model) {

        Specification< GoodsTable> specification = handleConditon( model);
        Sort sort = new Sort( Sort.Direction.DESC, "id");
        Pageable pageable = new PageRequest( page.getPage()-1, page.getLimit(), sort);
        Page< GoodsTable> resultPage = dao.findAll( specification, pageable);
        return resultPage;
    }

    public List< GoodsTable> list( GoodsModel model) {
        Specification< GoodsTable> specification = handleConditon( model);
        Sort sort = new Sort( Sort.Direction.DESC, "id");
        List< GoodsTable> tables = dao.findAll( specification, sort);
        return tables;
    }

    public void add( GoodsModel model) {
        GoodsTable table = null;
        if( model.getId() == null){//新增，把model里面的属性全部复制到新的table里面
            table = ModelUtils.copySignModel( model, GoodsTable.class);
        }else{//修改，把model里面的[非空]属性赋值到数据库里面查询的table里面
            table = dao.findOne( model.getId());
            ModelUtils.copySignModel( model, table);
        }
        dao.save( table);
    }

    /**
     * 发票审核通过的时候，初始化一条商品数据
     * @param model
     */
    public void initGoods( ConsumerRecordModel model) throws Exception {
        Integer monthNumber = DateFormatUtil.getMonth( model.getDateDeDepense());
        GoodsTable goodsTable = new GoodsTable();
        goodsTable.setCustomHouse( model.getCustomHouse());
        goodsTable.setConsumerRecordId( model.getId());
        goodsTable.setCreateTime( new Date());
        goodsTable.setUpdateTime( new Date());
        goodsTable.setStatus( "1");
        goodsTable.setStoreCount( 1);
        goodsTable.setPrice( Double.valueOf( model.getMontantTTC()));//商品总金额
        goodsTable.setRatePrice( Math.abs( model.getInvoiceMoney() != null ? Double.valueOf( model.getInvoiceMoney()) : 0));//商品税额
        goodsTable.setPurePrice( Math.abs( goodsTable.getPrice()) - Math.abs( goodsTable.getRatePrice()));//单个金额，为上传发票金额的免税金额。 为发票金额 -  TVA
        goodsTable.setSellPrice( handleGoodsSellPrice( Math.abs( goodsTable.getPurePrice())));//单个金额* （1+利润率%）
        goodsTable.setMonth( monthNumber);
        goodsTable.setAdminUserId( model.getImportUserId());
        DataDefineTable customerHouse = dataDefineDao.findByTypeAndDataValue( DataDefineTypeEnum.CUSTOMHOUSE, model.getCustomHouse());
        //商品名称为固定前缀加上海关名称
        goodsTable.setName( CommonConfig.GOODS_NAME_PROFIX + customerHouse.getDataKey());

        //获取当月该类商品根据order从大到小排序，当前商品的需要则为查询回来的第一条的需要+1 海关码和商品一一对应，所以 通过月份和 海关码查询
        List< GoodsTable> goodsTables = dao.findAllByMonthOrderByNumberDesc( monthNumber);
        if( goodsTables == null || goodsTables.size() == 0){
            goodsTable.setOrderG( 1);
        }else{
            goodsTable.setOrderG( goodsTables.get( 0).getOrderG() + 1);
        }
        getGoodsNumber( goodsTable, model.getDateDeDepense());
        model.setGoodsTable( goodsTable);
        dao.save( goodsTable);
        model.setGoodsId( goodsTable.getId());
        //发票图片上添加文字
        ConsumerRecordTable consumerRecordTable = consumerRecordDao.getOne( model.getId());
        String totalInvoiceImg = consumerRecordTable.getInvoiceImg();
        if( totalInvoiceImg != null && !totalInvoiceImg.equals( "")){
            String[] invoiceImgArr = totalInvoiceImg.split( ";");
            for( int i = 0; i < invoiceImgArr.length; i++){
                String invoiceImg = invoiceImgArr[i];
                if( invoiceImg != null && !invoiceImg.equals( "")){
                    invoiceImg = FileUtils.transferClientFileUrl( invoiceImg, baseClientDir, baseServerDir);
                    WaterMarkUtil.addWaterMark( invoiceImg, invoiceImg, goodsTable.getNumber());
                    invoiceImgArr[i] = invoiceImg;
                }
            }
            String pdfPath = FileUtils.transferClientFileUrl( consumerRecordTable.getInvoice(), baseClientDir, baseServerDir);
            PdfUtil.mergeImgsToPdf( invoiceImgArr, pdfPath, baseServerDir);
        }
    }

    public void del( String ids){
        List< GoodsTable> tables = new ArrayList<>();
        String[] idArr = ids.split( ",");
        for( String id : idArr){
            GoodsTable table = new GoodsTable();
            table.setId( Long.valueOf( id));
            tables.add( table);
        }
        dao.deleteInBatch( tables);
    }

    public GoodsTable get( Long id){
        return dao.getOne( id);
    }

    public Double sumSellPrice( String goodsIds){
        if( StringUtils.isEmpty( goodsIds)){
            return 0.00;
        }
        String[] idArr = goodsIds.split( ",");
        Double sellPrice = 0.00;
        for( String id : idArr){
            GoodsTable table = dao.getOne( Long.valueOf( id));
            sellPrice += Math.abs( table.getSellPrice());
        }
        return sellPrice;
    }

    /**
     * 组装查询条件
     * @return
     */
    private Specification< GoodsTable> handleConditon( GoodsModel model){
        Specification< GoodsTable> specification = new Specification< GoodsTable>() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                Predicate predicate = cb.conjunction();
                //判断权限，判断是否有查询所有数据的权限userId
                AdminUserTable adminUserTable = userAdminDao.findOne( model.getAdminUserId());
                String roleContent = adminUserTable.getRole().getContent();
                //如果没有查看所有数据的权限， 则直接根据 记录所属员工id来查询
                if( !PrivateConfig.checkPrivalege( roleContent, PrivateConfig.CONSUMER_LIST_ALL)){
                    predicate.getExpressions().add( cb.equal( root.get( "adminUserId").as( Long.class), adminUserTable.getId()));
                }
                //判断商品id是否在ids里面
                if( !StringUtils.isEmpty( model.getIds())){
                    List<Integer> ids = new ArrayList<>();
                    for( String i : model.getIds().split( ",")){
                        ids.add( Integer.valueOf( i));
                    }
                    predicate.getExpressions().add( root.get( "id").as( Long.class).in( ids));
                }else{
                    if( !StringUtils.isEmpty( model.getStatus())){
                        predicate.getExpressions().add( cb.equal( root.get( "status").as( String.class), model.getStatus()));
                    }
                    if( model.getStoreCount() != null && !model.getStoreCount().equals( 0)){
                        predicate.getExpressions().add( cb.equal( root.get( "storeCount").as( Integer.class),  model.getStoreCount()));
                    }
                }
                if( !StringUtils.isEmpty( model.getJobNumber())){
                    List<AdminUserTable> users = userAdminDao.findByJobNumberLike( "%" + model.getJobNumber() + "%");
                    if( users!= null && users.size() > 0){
                        CriteriaBuilder.In<Long> in = cb.in( root.get( "adminUserId"));
                        for( AdminUserTable user : users){
                            in.value( user.getId());
                        }
                        predicate.getExpressions().add( in);
                    }else{
                        CriteriaBuilder.In<Long> in = cb.in( root.get( "adminUserId"));
                        in.value( -1l);
                        predicate.getExpressions().add( in);
                    }
                }

                return predicate;
            }
        };
        return specification;
    }

    /**
     * 这里时间应该是消费记录的消费时间，不是当前系统时间
     * 生成规则   商品名称+员工号后两位+年（两位）+月（两位）+（该月该类商品的序号）
     * @param dateDeDepense
     * @return
     */
    private void getGoodsNumber( GoodsTable goodsTable, String dateDeDepense){
        int sequence = goodsTable.getOrderG();
        String res = "";
        //在不足4位的前面补0
        String sequenceStr = "0";
        if( sequence < 10){
            sequenceStr = "000" + sequence;
        }else if( sequence < 100){
            sequenceStr = "00" + sequence;
        }else if( sequence < 1000){
            sequenceStr = "0" + sequence;
        }else{
            sequenceStr = "" + sequence;
        }
        String monthStr = "";
        Date consumerDate = DateFormatUtil.parse( dateDeDepense);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime( consumerDate);
        Integer currMonth = calendar.get( Calendar.MONTH) + 1;
        if( currMonth < 10){
            monthStr = "0" + currMonth;
        }else{
            monthStr = "" + currMonth;
        }
        res += monthStr + " " + calendar.get( Calendar.YEAR) + " " + sequenceStr;
        goodsTable.setNumber( res);
    }

    private Double handleGoodsSellPrice( Double price){
        SystemparamTable systemparamTable = systemparamDao.getFirstByIdNotNull();
        double pp = price * ( 1.00 + ( Double.valueOf( systemparamTable.getGoodsSellRate().replace( "%", ""))/100));
        pp = (double)(Math.round(pp*100)/100.0);
        return pp;
    }
}
